/*
 * File Name：FileUtils.java
 * Copyright：Copyright 2008-2014 CiWong.Inc. All Rights Reserved.
 * Description： FileUtils.java
 * Modify By：res-jxliu
 * Modify Date：2014-5-28
 * Modify Type：Add
 */
package com.ciwong.libs.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;

/**
 * 习网文件工具类
 *
 * @author res-jxliu
 * @version ciwong v.1.0 2014-5-28
 * @since ciwong v.1.0
 */
public class FileUtils {
    /**
     * 获取配置信息
     */
    public static final String NEW_LINE = System.getProperty("line.separator");

    /**
     * 习网存储根目录
     */
    public static final String CW_ROOT_FILE_NAME = "ciwong";

    /**
     * 压缩解压编码
     */
    private static final String UTF_8 = "UTF-8";
    protected static Context mContext;
    /**
     * 设置上下文，供后面使用<br />
     * 注:此方法必须要在应用开启时或是调用内部方法前调用<br />
     * 否则可能会报空指针异常
     *
     * @param context
     *            上下文
     */
    public static void setContext(Context context)
    {
        mContext = context;
    }

    /**
     *
     * 获取上下文
     *
     * @return mContext
     */
    public static Context getContext()
    {
        return mContext;
    }
    private static FileFilter filterDirectory = new FileFilter() {
        @Override
        public boolean accept(File file) {
            return file.isDirectory();
        }
    };

    /**
     * 日志输出文件夹目录
     */
    private static String logPath = null;

    /**
     * 设置日志输出文件夹目录
     *
     * @param logPath 路径
     */
    public static void setLogPath(String logPath) {
        FileUtils.logPath = logPath;
    }

    /**
     * 获取日志输出文件夹目录
     *
     * @return logPath
     */
    public static String getLogPath() {
        return logPath;
    }

    /**
     * SD根目录
     *
     * @return 习网根目录
     */
    public static File getSDCardFolder() {
        File root = null;
        if (Environment.MEDIA_MOUNTED.equals(Environment
                .getExternalStorageState())) {
            root = Environment.getExternalStorageDirectory();
        } else {
            root = Environment.getDataDirectory();
        }
        return root;
    }

    /**
     * 获取应用程序缓存目录
     *
     * @param packageName 包名
     * @return File
     */
    public static File getSDAppCacheFolder(String packageName) {
        File file = new File(getSDCardFolder(), "Android" + File.separator
                + "data" + File.separator + packageName + File.separator
                + "file");
        if (!file.exists()) {
            file.mkdirs();
        }
        return file;
    }

    /**
     * SD根目录
     *
     * @return SD根目录
     */
    public static String getSDCardPath() {
        return getSDCardFolder().getAbsolutePath();
    }

    /**
     * 习网根目录
     *
     * @return 习网根目录
     */
    public static String getCiwongRoot() {
//        return getCiwongRootFolder().getAbsolutePath();
        return mContext.getApplicationContext().getExternalFilesDir(null).getAbsolutePath();
    }

    /**
     * 习网根目录
     *
     * @return 习网根目录
     */
    public static File getCiwongRootFolder() {
        File root = new File(getSDCardFolder(), CW_ROOT_FILE_NAME);
        if (!root.exists()) {
            root.mkdirs();
        }
        return root;
    }

    /**
     * 文件过滤器
     *
     * @author res-jxliu
     */
    static class Filter implements FileFilter {
        private int len;

        private String extend;

        public Filter(int len, String extend) {
            this.len = len;
            this.extend = extend;
        }

        @Override
        public boolean accept(File file) {
            String temp = file.getName();
            if (temp.length() <= len) {
                return false;
            }
            temp = temp.substring(temp.length() - len);
            return extend.equals(temp);
        }

    }

    /**
     * filter
     *
     * @param extend  extend
     * @param file    file
     * @param mFilter mFilter
     * @return File列表
     */
    public static List<File> filter(final String extend, File file,
                                    Filter mFilter) {
        List<File> retFiles = new ArrayList<File>();
        File[] files = file.listFiles(filterDirectory);
        int len = 0;
        if (files != null) {
            len = files.length;
            for (int i = 0; i < len; i++) {
                final File temp = files[i];
                retFiles.addAll(filter(extend, temp, mFilter));
            }
        }
        files = file.listFiles(mFilter);
        if (files != null) {
            len = files.length;
            for (int i = 0; i < len; i++) {
                retFiles.add(files[i]);
            }
        }
        return retFiles;
    }

    /**
     * 复制文件
     *
     * @param fromFileUrl 旧文件地址和名称
     * @param toFileUrl   新文件地址和名称
     */
    public static void copyFile(String fromFileUrl, String toFileUrl) {
        File fromFile = new File(fromFileUrl);
        File toFile = new File(toFileUrl);
        if (!fromFile.exists()) {
            return;
        }
        if (!fromFile.isFile()) {
            return;
        }
        if (!fromFile.canRead()) {
            return;
        }
        // 复制到的路径如果不存在就创建
        if (!toFile.getParentFile().exists()) {
            toFile.getParentFile().mkdirs();
        }

        // if (!toFile.canWrite())
        // {
        // return;
        // }
        if (fromFile.getParent().equals(toFile.getParent())) {
            fromFile.renameTo(toFile);
        } else {
            try {
                FileInputStream fosfrom = new FileInputStream(
                        fromFile);
                FileOutputStream fosto = new FileOutputStream(toFile);
                byte bt[] = new byte[1024];
                int c;
                while ((c = fosfrom.read(bt)) > 0) {
                    fosto.write(bt, 0, c); // 将内容写到新文件当中
                }
                // 关闭数据流
                fosfrom.close();
                fosto.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 复制文件(单个文件)
     *
     * @param in      拷贝文件流
     * @param path    保存路径
     * @param isCover 是否复盖
     */
    public static void copy(InputStream in, String path, boolean isCover) {
        try {
            File outFile = new File(path);
            if (!outFile.exists() || isCover) {
                FileOutputStream out = new FileOutputStream(outFile);
                int len;
                byte[] buffer = new byte[1024];
                while ((len = in.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
                out.flush();
                out.close();
                in.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void copy(InputStream in, File outFile, boolean isCover) {
        try {
            if (!outFile.exists() || isCover) {
                FileOutputStream out = new FileOutputStream(outFile);
                int len;
                byte[] buffer = new byte[1024];
                while ((len = in.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
                out.flush();
                out.close();
                in.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 复制文件(单个文件)
     *
     * @param in      拷贝文件流
     * @param path    保存路径
     * @param isCover 是否复盖
     */
    public static void copySingle(InputStream in, String path, boolean isCover) {
        copy(in, path, isCover);
    }

    /**
     * 复制文件(单个文件),默认为覆盖
     *
     * @param in   拷贝文件流
     * @param path 保存路径
     */
    public static void copySingle(InputStream in, String path) {
        copy(in, path, true);
    }

    /**
     * 复制文件
     *
     * @param file    要拷贝的文件
     * @param path    保存路径
     * @param isCover 是否覆盖
     */
    public static void copy(File file, String path, boolean isCover) {
        if (file.isDirectory()) {
            if (!file.exists()) {
                file.mkdirs();
            }
            File[] files = file.listFiles();
            for (File f : files) {
                copy(f, path + "/" + f.getName(), isCover);
            }
        } else {
            if (!file.exists() || isCover) {
                try {
                    FileOutputStream out = new FileOutputStream(new File(path));
                    InputStream in = new FileInputStream(file);
                    int len;
                    byte[] buffer = new byte[1024];
                    while ((len = in.read(buffer)) > 0) {
                        out.write(buffer, 0, len);
                    }
                    out.flush();
                    out.close();
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 将文本内容存储至指定的文件
     *
     * @param content 文本内容
     * @param path    文件路径
     * @throws IOException
     */
    public static void save(String content, String path) throws IOException {
        FileOutputStream out = new FileOutputStream(new File(path));
        out.write(content.getBytes(UTF_8));
        out.close();
    }

    /**
     * 将文本内容存储至指定的文件
     *
     * @param content 文本内容
     * @param path    文件路径
     * @param append  是否追加
     * @throws IOException
     */
    public static void save(String content, String path, boolean append)
            throws IOException {
        FileOutputStream out = new FileOutputStream(new File(path), append);
        out.write(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF});
        out.write(content.getBytes(UTF_8));
        out.close();
    }

    private static boolean validLogFile() {
        if (logPath == null) {

            return false;
        }
        return true;
    }

    /**
     * 保存信息
     *
     * @param content 文本内容
     */
    public static void logInfo(String content) {
        if (!validLogFile()) {
            return;
        }
        File f = new File(logPath + "/log");
        if (!f.exists()) {
            return;
        }
        content = "------------------------Info:"
                + formatDate1(System.currentTimeMillis())
                + "------------------------" + NEW_LINE + content + NEW_LINE;
        try {
            save(content,
                    f.getAbsolutePath() + "/"
                            + formatDate(System.currentTimeMillis()) + "_.ilog",
                    true);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 保存信息
     *
     * @param content 文本内容
     */
    public static void logDebug(String content) {
        if (!validLogFile()) {
            return;
        }
        File f = new File(logPath + "/log");
        if (!f.exists()) {
            return;
        }
        content = "------------------------Debug:"
                + formatDate1(System.currentTimeMillis())
                + "------------------------" + NEW_LINE + content + NEW_LINE;
        try {
            save(content,
                    f.getAbsolutePath() + "/"
                            + formatDate(System.currentTimeMillis()) + ".dlog",
                    true);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 保存信息
     *
     * @param content 文本内容
     */
    public static void logWarning(String content) {
        if (!validLogFile()) {
            return;
        }
        File f = new File(logPath + "/log");
        if (!f.exists()) {
            return;
        }
        content = "------------------------Warning:"
                + formatDate1(System.currentTimeMillis())
                + "------------------------" + NEW_LINE + content + NEW_LINE;
        try {
            save(content,
                    f.getAbsolutePath() + "/"
                            + formatDate(System.currentTimeMillis()) + ".wlog",
                    true);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 保存信息
     *
     * @param content 文本内容
     */
    public static void logError(String content) {
        if (!validLogFile()) {
            return;
        }
        File f = new File(logPath + "/log");
        if (!f.exists()) {
            return;
        }
        content = "------------------------Error:"
                + formatDate1(System.currentTimeMillis())
                + "------------------------" + NEW_LINE + content + NEW_LINE;
        try {
            save(content,
                    f.getAbsolutePath() + "/"
                            + formatDate(System.currentTimeMillis()) + ".elog",
                    true);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 删除文件
     *
     * @param deleteFiles 文件或文件夹列表
     * @return boolean
     */
    public static boolean delete(File[] deleteFiles) {
        if (deleteFiles == null) {
            return false;
        }
        boolean retVal = true;
        for (File f : deleteFiles) {
            retVal = delete(f);
            if (!retVal) {
                break;
            }
        }
        return retVal;
    }

    /**
     * 删除文件
     *
     * @param deleteFile 文件或文件夹
     * @return boolean
     */
    public static boolean delete(File deleteFile) {
        if (!deleteFile.exists()) {
            return false;
        }
        boolean retVal = false;
        if (deleteFile.isDirectory()) {
            File[] fs = deleteFile.listFiles();
            // int len = fs == null ? 0 : fs.length;
            // for (int i = 0; i < len; i++)
            // {
            retVal = delete(fs);
            // }
        }
        retVal = deleteFile.delete();
        return retVal;
    }

    /**
     * 删除文件
     *
     * @param path 文件或文件夹的路径
     * @return boolean
     */
    public static boolean delete(String path) {
        return delete(new File(path));
    }

    /**
     * 获取文件大小(单位kb)
     *
     * @param path 文件路径
     * @return 文件大小, 若为文件夹返回-1,若不存在则返回-2
     */
    public static int getFileSize(String path) {
        int ret = -1;
        File f = new File(path);
        if (!f.exists()) {
            ret = -2;
        } else if (!f.isDirectory()) {
            ret = (int) (f.length() / 1024);
        }
        return ret;
    }

    // public static boolean copySingle(String inPath, String outPath)
    // {
    // FileDescriptor fd = new FileDescriptor();
    // File inFile = new File(inPath);
    // }

    /**
     * 拷贝文件(单个文件)
     *
     * @param inFd    输入{@link FileDescriptor}
     * @param outPath 输出文件路径
     * @return 是否成功
     * @throws IOException IO异常
     */
    public static boolean copySingle(FileDescriptor inFd, File outPath)
            throws IOException {
        int length = 2097152;
        FileInputStream in = new FileInputStream(inFd);
        FileOutputStream out = new FileOutputStream(outPath);
        FileChannel inC = in.getChannel();
        FileChannel outC = out.getChannel();
        ByteBuffer b = null;
        while (true) {
            if (inC.position() == inC.size()) {
                inC.close();
                outC.close();
                return true;
            }
            if ((inC.size() - inC.position()) < length) {
                length = (int) (inC.size() - inC.position());
            } else {
                length = 2097152;
            }
            b = ByteBuffer.allocateDirect(length);
            inC.read(b);
            b.flip();
            outC.write(b);
            outC.force(false);
        }
    }

    /**
     * 保存文件
     *
     * @param target 文件
     * @param in     输入流
     */
    public static void save(File target, InputStream in) {
        try {
            FileOutputStream out = new FileOutputStream(target);
            int len;
            byte[] buffer = new byte[1024];
            while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
            out.flush();
            out.close();
            in.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 保存文件
     *
     * @param target 文件
     * @param data   二进制数组
     */
    public static void save(File target, byte[] data) {
        try {
            FileOutputStream out = new FileOutputStream(target);
            out.write(data);
            out.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 保存临时文件
     *
     * @param result       输入流
     * @param tempFileName 临时文件名称
     * @return 临时文件
     */
    private static File saveTemp(InputStream result, String tempFileName) {
        File storeFile = new File(getCiwongRoot() + File.separator + "temp");
        if (!storeFile.exists()) {
            storeFile.mkdirs();
        }
        File temp = null;
        try {

            temp = new File(storeFile, tempFileName);
            FileOutputStream out = new FileOutputStream(new File(storeFile,
                    tempFileName));
            int len;
            byte[] buffer = new byte[1024];
            while ((len = result.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return temp;
    }

    /**
     * 日期转换(yyyy-MM-dd)<br />
     * 转换中出现异常则返回null
     *
     * @param dateLong 日期长整型
     * @return 转换后的格式
     */
    public static String formatDate(long dateLong) {
        try {
            java.util.Date date = new java.util.Date(dateLong);
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            return format.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 日期转换(yyyy-MM-dd HH:mm:ss)<br />
     * 转换中出现异常则返回null
     *
     * @param dateLong 日期长整型
     * @return 转换后的格式
     */
    public static String formatDate1(long dateLong) {
        try {
            java.util.Date date = new java.util.Date(dateLong);
            SimpleDateFormat format = new SimpleDateFormat(
                    "yyyy-MM-dd HH:mm:ss");
            return format.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取assets包下的图片
     *
     * @param resources resources
     * @param fileName  要获取图片的文件名（如：no_1.png）
     * @return 返回该图片的Bitmap
     */
    public static Bitmap getImageFromAssetsFile(Resources resources,
                                                String fileName) {
        Bitmap bitmap = null;
        InputStream is = null;
        AssetManager am = resources.getAssets();
        try {
            is = am.open(fileName);
            bitmap = BitmapFactory.decodeStream(is);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return bitmap;
    }

    /**
     * 数据压缩
     *
     * @param data 压缩的数据
     * @return byte[]
     * @throws Exception 抛出的异常
     */
    public static byte[] compress(byte[] data) throws Exception {
        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        // 压缩
        compress(bais, baos);

        byte[] output = baos.toByteArray();

        baos.flush();
        baos.close();

        bais.close();

        return output;
    }

    private static void compress(InputStream is, OutputStream os)
            throws Exception {

        GZIPOutputStream gos = new GZIPOutputStream(os);

        int count;
        byte data[] = new byte[1024];
        while ((count = is.read(data, 0, data.length)) != -1) {
            gos.write(data, 0, count);
        }

        gos.finish();

        gos.flush();
        gos.close();
    }

    /**
     * 数据解压缩
     *
     * @param data 压缩的数据
     * @return byte[]
     * @throws Exception 抛出的异常
     */
    public static byte[] decompress(byte[] data) throws Exception {
        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        // 解压缩

        decompress(bais, baos);

        data = baos.toByteArray();

        baos.flush();
        baos.close();

        bais.close();

        return data;
    }

    private static void decompress(InputStream is, OutputStream os)
            throws Exception {

        GZIPInputStream gis = new GZIPInputStream(is);

        int count;
        byte data[] = new byte[1024];
        while ((count = gis.read(data, 0, data.length)) != -1) {
            os.write(data, 0, count);
        }

        gis.close();
    }

}
